package org.hepeng.commons.serializer;


import org.hepeng.commons.exception.ApplicationRuntimeException;
import org.hepeng.commons.util.ClassUtils;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.Objects;

/**
 * @author he peng
 */
public class ObjectSerializationUtils {

    public static void serializableCheck(Object object) {
        if (!(object instanceof Serializable)) {
            throw new IllegalArgumentException("requires a Serializable payload " +
                    "but received an object of type [" + object.getClass().getName() + "]");
        }
    }

    public static <T> ObjectSerializer<T> newObjectSerializer(SupportSerializer supportSerializer , Class<T> serializationClass) {
        Assert.notNull(serializationClass , "serializationClass must not be null");
        if (Objects.isNull(supportSerializer)) {
            supportSerializer = SupportSerializer.JDK;
        }

        Class<? extends ObjectSerializer> superClass = null;
        switch (supportSerializer) {
            default : break;
            case JDK: {
                superClass = JdkObjectSerializer.class;
            } break;
            case KRYO: {
                superClass = KryoObjectSerializer.class;
            } break;
            case HESSIAN: {
                superClass = Hessian2ObjectSerializer.class;
            } break;
        }

        return getObjectSerializer(superClass , serializationClass);
    }

    private static ObjectSerializer getObjectSerializer(Class<? extends ObjectSerializer> superClass , Class serializationClass) {
        Class newSubClass = newSubClass(superClass , serializationClass);
        try {
            return (ObjectSerializer) newSubClass.newInstance();
        } catch (Throwable t) {
            throw new ApplicationRuntimeException(t);
        }
    }


    private static Class newSubClass(Class<? extends ObjectSerializer> superClass , Class serializationClass) {
        String superClassPackageName = superClass.getPackage().getName();
        String superClassSimpleName = superClass.getSimpleName();
        String newPackageName = superClassPackageName;
        String newClassName = "Sub" + superClassSimpleName + "$" + serializationClass.getSimpleName();
        StringBuilder codeBuilder = new StringBuilder("package ").append(newPackageName).append(";");

        codeBuilder.append(" public class ").append(newClassName)
                .append(" extends ")
                .append(superClass.getName())
                .append("<").append(serializationClass.getName()).append(">")
                .append(" {").append("public ").append(newClassName)
                .append("() ").append("{")
                .append("super.serializationClass = org.hepeng.commons.util.ClassUtils.getSingleGenericSuperclass(getClass());")
                .append("}")
                .append("}");

        String qualifiedClassName = newPackageName + "." + newClassName;
        return ClassUtils.compileFromJavaCode(qualifiedClassName , codeBuilder.toString());
    }

}
